package com.hzw.saas.web.app.product.controller;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;

import com.hzw.saas.api.product.IProductUpdateService;
import com.hzw.saas.api.product.bo.ProductVersionBO;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.exception.DefaultSaasException;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.storage.service.IFileStorageService;
import com.hzw.saas.common.util.HttpContextUtils;
import cn.hutool.core.io.FileUtil;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author EZ09
 * @since 08/03/2021
 */
@Controller
@Validated
@RequiredArgsConstructor
@Slf4j
@Api(tags = "产品升级")
public class ProductUpdateController {

    private final IProductUpdateService productUpdateService;
    private final IFileStorageService fileStorageService;

    @GetMapping("/product/{productName}/release/versions")
    @SysLog
    @ApiOperation(value = "获取软件产品的版本列表", notes = "获取某个软件产品的版本列表（当前用户有版本权限），含版本号和版本描述。如果用户有多个软件版本权限，可在这些版本之间切换更新")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "productName", value = "产品名称", dataType = "String", paramType = "path", required = true),
    })
    @ApiOperationSort(11)
    public ResponseEntity<List<ProductVersionBO>> listProductVersions(@PathVariable String productName) {
        String userId = SecurityUtils.getUser().getUserId();
        List<ProductVersionBO> result = productUpdateService.listProductVersions(userId, productName);
        return ResponseEntity.ok(result);
    }

    @GetMapping("/product/{productName}/release/{directoryName}/metadata")
    @SysLog(operation = "下载某个软件产品特定版本的描述文件", mode = 3)
    @ApiOperation(value = "下载某个软件产品特定版本的描述文件", notes = "描述文件(version.bin)包含所有文件的相对路径（含文件名）、文件版本号、文件摘要（MD5）。注：文件版本号的排序规则")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "access_token", value = "用户token（或在请求头设置Authorization）", dataType = "String", paramType = "query", required = false),
        @ApiImplicitParam(name = "productName", value = "产品名称", dataType = "String", paramType = "path", required = true),
        @ApiImplicitParam(name = "directoryName", value = "产品目录", dataType = "String", paramType = "path", required = true)
    })
    @ApiOperationSort(12)
    public void listProductFiles(HttpServletRequest request, HttpServletResponse response, @PathVariable String productName, @PathVariable String directoryName) {
        String userId = SecurityUtils.getUser().getUserId();
        File metadata = productUpdateService.getProductMetadata(userId, productName, directoryName);
        try (OutputStream fos = response.getOutputStream()) {
            HttpContextUtils.setFileDownloadHeader(request, response, metadata.getName(), metadata.length());
            fileStorageService.read(FileUtil.getAbsolutePath(metadata), fos, 0);
            response.flushBuffer();
            log.debug("下载产品描述文件完成...");
        } catch (IOException e) {
            log.error("下载产品描述文件失败", e);
            throw DefaultSaasException.build("下载产品描述文件失败");
        }
    }

    @GetMapping("/product/{productName}/release/{directoryName}/file")
    @SysLog(operation = "下载某个软件产品特定版本的文件", mode = 3)
    @ApiOperation(value = "下载某个软件产品特定版本的文件", notes = "根据软件产品ID、版本号、文件相对路径（含文件名）下载软件仓库中对应的文件")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "access_token", value = "用户token（或在请求头设置Authorization）", dataType = "String", paramType = "query", required = false),
        @ApiImplicitParam(name = "productName", value = "产品名称", dataType = "String", paramType = "path", required = true),
        @ApiImplicitParam(name = "directoryName", value = "产品目录", dataType = "String", paramType = "path", required = true),
        @ApiImplicitParam(name = "filePath", value = "文件相对路径（含文件名）", dataType = "String", paramType = "query", required = true)
    })
    @ApiOperationSort(13)
    public void downloadProductFile(HttpServletRequest request, HttpServletResponse response, @PathVariable String productName, @PathVariable String directoryName, @NotBlank String filePath) {
        String userId = SecurityUtils.getUser().getUserId();
        File file = productUpdateService.getProductFile(userId, productName, directoryName, filePath);
        try (OutputStream fos = response.getOutputStream()) {
            HttpContextUtils.setFileDownloadHeader(request, response, file.getName(), file.length());
            fileStorageService.read(FileUtil.getAbsolutePath(file), fos, 0);
            response.flushBuffer();
            log.debug("下载产品文件完成...");
        } catch (IOException e) {
            log.error("下载产品文件失败", e);
            throw DefaultSaasException.build("下载产品文件失败");
        }
    }

}
